// EG4DCSD.cc -- implementation of the class for Sensitive Detectors of DCs
// Created: Jan. 22, 2019, by Asia SUN, asia.rabbit@163.com
// Last Modified: Jan. 22, 2019 by Asia SUN

#include "EG4DCSD.h"
#include "EG4DCHit.h"
#include "G4SDManager.hh"
#include "G4HCofThisEvent.hh"
#include "G4Track.hh"
#include "G4Step.hh"
#include "G4VTouchable.hh"
#include "G4HCofThisEvent.hh"

EG4DCSD::EG4DCSD(string name) : G4VSensitiveDetector(name), fHC{0}{
  collectionName.insert("DCC");
  collectionName.insert("DCC2"); // secondaries
  for(auto &i : fHCID) i = -1;
} // end ctor

EG4DCSD::~EG4DCSD(){}

// will be invoked at the beginning of each event
void EG4DCSD::Initialize(G4HCofThisEvent *hce){
  static auto sdm = G4SDManager::GetSDMpointer();
  for(int i = 0; i < kNHC; i++){
    fHC[i] = new EG4DCHC(SensitiveDetectorName, collectionName[i]);
    if(fHCID[i] < 0) fHCID[i] = sdm->GetCollectionID(fHC[i]);
    hce->AddHitsCollection(fHCID[i], fHC[i]);
  } // end for over hit collections
} // end member function Iniitalize

bool EG4DCSD::ProcessHits(G4Step *step, G4TouchableHistory *){
  // identify the particle and the track //
  G4Track *track = step->GetTrack();
  const G4ParticleDefinition *particle = track->GetParticleDefinition();
  const double charge = particle->GetPDGCharge();
  if(!charge) return false; // DC only reacts to charged particles
  // parentID: 0: primary; >0: secondary; <0: postponed from previous ev
  // trackID: 1: primary; >1: secondaries
  const int pid = track->GetParentID(), tid = track->GetTrackID();
  const int hcid = 0 == pid ? 0 : 1;
  const double de = step->GetTotalEnergyDeposit();

  // we only select one (use the 1st for convenience) hit for the primary
  G4StepPoint *pp = step->GetPreStepPoint();
  const G4VTouchable *th = pp->GetTouchable();
  const int dcid = th->GetCopyNumber(1), lid = th->GetCopyNumber(0);
  int ix = -1;
  EG4DCHC *hc = fHC[hcid];
  for(int i = 0; i < int(hc->entries()); i++){
    if((*hc)[i]->GetDCId() == dcid && (*hc)[i]->GetWireLayerId() == lid){
      (*hc)[i]->AddEdep(de);
      ix = i; break;
    } // end if
  } // end for
  if(-1 == ix){
    // if not, create a new hit and set it to the collection
    EG4DCHit *hit = new EG4DCHit();
    hit->SetHitType(hcid);
    hit->SetName(particle->GetParticleName());
    hit->SetParentId(pid);
    hit->SetTrackId(tid);
    hit->SetDCId(dcid); hit->SetWireLayerId(lid);
    hit->SetLV(th->GetVolume()->GetLogicalVolume());
    hit->SetMass(particle->GetPDGMass());
    hit->SetCharge(charge);
    hit->SetTime(pp->GetGlobalTime());
    hit->SetVelocity(pp->GetVelocity());
    hit->SetKineticEnergy(pp->GetKineticEnergy());
    hit->SetEdep(de);
    hit->SetTrkLen(track->GetTrackLength());
    hit->SetMomentum(pp->GetMomentum());
    const auto &transform = th->GetHistory()->GetTopTransform();
    transform.Inverse();
    hit->SetRot(transform.NetRotation());
    hit->SetPos(transform.NetTranslation());
    hit->SetHitPos(pp->GetPosition());
    hc->insert(hit);
  } // end else

  return true;
} // end member function ProcessHits
